package com.gpStudy.Netty.rpc.registry;

import com.gpStudy.Netty.rpc.protocol.InvokerProtocol;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class RegistryHandler extends ChannelInboundHandlerAdapter {


    private List<String> classNames = new ArrayList<>();

    private Map<String, Object> registryMap = new HashMap<>();

    public RegistryHandler() {

        // 1、根据一个包名将所有符合条件的class 全部扫描出来，放到一个容器中(简化版本)
        //   如果是分布式，就读配置文件
        scannerClass("com.gpStudy.Netty.rpc.provider");

        // 2、给每一个对应的class起一个唯一的名字，作为服务名称，保存到一个容器中
        doRegistry();

    }





    /**
     *  有客户端连上的时候会回调
     *  // 3、当有客户端连接过来之后，就会获取协议内容 InvokerProtocol的对象
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        Object result = new Object();

        InvokerProtocol request = (InvokerProtocol) msg;
        // 4、要去注册好的容器中找到符合条件的服务
        if (registryMap.containsKey(request.getClassName())) {
            Object service = registryMap.get(request.getClassName());
            Method method = service.getClass().getMethod(request.getMethodName(), request.getParams());
            result = method.invoke(service, request.getValues());
        }
        
        // 5、通过远程调用 Provider 得到返回结果，并回复给客户端
        ctx.write(result);
        ctx.flush();
        ctx.close();
    }

    /**
     * 连接发生异常的时候回调
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		 cause.printStackTrace();    
         ctx.close(); 
    }
    private void scannerClass(String packageName) {

        URL url = this.getClass().getClassLoader().getResource(packageName.replaceAll("\\.", "/"));
        File classPath = new File(url.getFile());

        for (File file : classPath.listFiles()){
            if (file.isDirectory())
                scannerClass(packageName+"."+file.getName());
            else{
                classNames.add(packageName+"."+file.getName().replace(".class",""));
            }
        }



    }
    private void doRegistry() {

        if (classNames.isEmpty())  return;

        for (String className : classNames){
            try {
                Class<?> clazz = Class.forName(className);
                Class<?> i = clazz.getInterfaces()[0];
                String serviceName = i.getName();

                // 本来这里存的应该是网络路径，从配置文件读取
                // 在调用的时候再去解析，这里直接用反射调用
                registryMap.put(serviceName, clazz.newInstance());

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }
}
